# -*- coding: utf-8 -*-
"""
@Author: BaiZe
@Description: 
@Date: 2025/6/19
"""

import pandas as pd
from jinja2 import Environment, FileSystemLoader


def compare_dataframes(df1, df2, key_columns):
    """
    比较两个DataFrame，识别新增、删除和修改的行
    """
    # 创建原始数据的副本（保留原始列顺序）
    df1_orig = df1.copy()
    df2_orig = df2.copy()

    # 设置索引并排序
    df1 = df1.set_index(key_columns).sort_index()
    df2 = df2.set_index(key_columns).sort_index()

    # 识别新增和删除的行
    added = df2[~df2.index.isin(df1.index)]
    deleted = df1[~df1.index.isin(df2.index)]

    # 识别修改的行
    common_keys = df1.index.intersection(df2.index)
    modified = []

    for key in common_keys:
        row1 = df1.loc[key]
        row2 = df2.loc[key]

        # 检查是否有差异
        if not row1.equals(row2):
            # 识别具体差异列
            diff_cols = []
            for col in df1.columns:
                val1 = row1[col]
                val2 = row2[col]
                # 处理NaN和None
                if pd.isna(val1) and pd.isna(val2):
                    continue
                elif pd.isna(val1) or pd.isna(val2) or val1 != val2:
                    diff_cols.append(col)
            # 安全获取原始行
            try:
                # 处理单列键和多列键的情况
                if len(key_columns) == 1:
                    key_value = key[0] if isinstance(key, tuple) else key
                    orig_row1 = df1_orig[df1_orig[key_columns[0]] == key_value].iloc[0].to_dict()
                    orig_row2 = df2_orig[df2_orig[key_columns[0]] == key_value].iloc[0].to_dict()
                else:
                    # 多列键的情况
                    mask1 = pd.Series(True, index=df1_orig.index)
                    mask2 = pd.Series(True, index=df2_orig.index)

                    for i, col in enumerate(key_columns):
                        key_val = key[i] if isinstance(key, tuple) else key
                        mask1 = mask1 & (df1_orig[col] == key_val)
                        mask2 = mask2 & (df2_orig[col] == key_val)

                    orig_row1 = df1_orig[mask1].iloc[0].to_dict()
                    orig_row2 = df2_orig[mask2].iloc[0].to_dict()

                # 将索引键转换为可显示格式
                if isinstance(key, tuple):
                    display_key = " | ".join(str(k) for k in key)
                else:
                    display_key = str(key)

                modified.append({
                    'key': display_key,
                    'old': orig_row1,
                    'new': orig_row2,
                    'diff_cols': diff_cols
                })
            except IndexError:
                # 处理找不到匹配行的情况
                print(f"警告: 找不到键 {key} 的匹配行，跳过此修改项")
                continue
            except Exception as e:
                print(f"处理键 {key} 时出错: {str(e)}")
                continue

    return {
        'added': added.reset_index().to_dict('records'),
        'deleted': deleted.reset_index().to_dict('records'),
        'modified': modified
    }


def generate_html_report(diff_results, output_path, per_page=10):
    """
    生成带分页的HTML报告
    """
    # 准备分页数据
    results = {
        'added': paginate(diff_results['added'], per_page),
        'deleted': paginate(diff_results['deleted'], per_page),
        'modified': paginate(diff_results['modified'], per_page)
    }

    # 获取所有列名（用于表头）
    all_columns = set()
    if diff_results['added']:
        all_columns.update(diff_results['added'][0].keys())
    if diff_results['deleted']:
        all_columns.update(diff_results['deleted'][0].keys())
    if diff_results['modified']:
        all_columns.update(diff_results['modified'][0]['old'].keys())

    columns = sorted(all_columns)

    # 设置Jinja2环境
    env = Environment(loader=FileSystemLoader('.'))
    template = env.get_template('report_template.html')

    # 渲染模板
    html = template.render(
        results=results,
        columns=columns,
        per_page=per_page
    )

    # 写入文件
    with open(output_path, 'w') as f:
        f.write(html)


def paginate(data, per_page):
    """
    将数据分页
    """
    if not data:
        return {'total': 0, 'pages': [], 'num_pages': 0}

    pages = []
    for i in range(0, len(data), per_page):
        page_data = data[i:i + per_page]
        page_num = (i // per_page) + 1
        pages.append({
            'number': page_num,
            'data': page_data,
            'start_index': i + 1,
            'end_index': min(i + per_page, len(data))
        })

    return {
        'total': len(data),
        'pages': pages,
        'num_pages': len(pages)
    }


# 示例用法
if __name__ == "__main__":
    # 更全面的示例数据（包含多列键）
    df11 = pd.DataFrame({
        'id': [1, 2, 3, 4, 6, 7],
        'name': ['Alice', 'Bob', 'Charlie', 'David', 'David', 'Eva'],
        'department': ['HR', 'IT', 'Finance', 'Marketing', 'Marketing','Marketing'],
        'salary': [5000, 7000, 6500, 6000, 8000, 9000],
        'join_date': ['2020-01-01', '2019-05-15', '2021-03-10', '2022-01-15','2022-01-15', '2023-02-20']
    })

    df22 = pd.DataFrame({
        'id': [1, 2, 4, 5],
        'name': ['Alice Smith', 'Bob', 'David', 'Eva'],
        'department': ['HR', 'IT', 'Marketing', 'Sales'],
        'salary': [5500, 7000, 6200, 7200],
        'join_date': ['2020-01-01', '2019-05-15', '2022-01-15', '2023-02-20']
    })

    # 关键列用于比较（单列键）
    key_columns1 = ['id']

    # 执行比较
    diff_results1 = compare_dataframes(df11, df22, key_columns1)

    # 生成HTML报告
    generate_html_report(diff_results1, 'diff_report.html', per_page=2)

    # 测试多列键
    print("\n测试多列键...")
    df3 = pd.DataFrame({
        'dept': ['HR', 'IT', 'HR', 'IT'],
        'emp_id': [101, 102, 103, 104],
        'name': ['Alice', 'Bob', 'Charlie', 'David'],
        'salary': [5000, 7000, 6500, 6000]
    })

    df4 = pd.DataFrame({
        'dept': ['HR', 'IT', 'HR', 'Finance'],
        'emp_id': [101, 102, 103, 105],
        'name': ['Alice Smith', 'Bob', 'Charlie Brown', 'Eva'],
        'salary': [5500, 7000, 6800, 7200]
    })

    # 多列键
    key_columns_multi = ['dept', 'emp_id']
    diff_results_multi = compare_dataframes(df3, df4, key_columns_multi)
    print(f"修改行数量: {len(diff_results_multi['modified'])}")
